﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac;
using HomeDump.Core.Contracts;
using Module = Autofac.Module;

namespace HomeDump.Server
{
	/// <summary>
	/// Module responsible for registering components with Autofac.
	/// </summary>
	internal class ServerModule : Module
	{
		/// <summary>
		/// Override to add registrations to the container.
		/// </summary>
		/// <param name="builder">
		/// The builder through which components can be registered.
		/// </param>
		/// <remarks>
		/// Note that the ContainerBuilder parameter is unique to this module.
		/// </remarks>
		protected override void Load(ContainerBuilder builder)
		{
			Requires.IsNotNull(builder);

			base.Load(builder);

			RegisterAssemblyTypes(
				builder,
				Assembly.Load("HomeDump.Core"),
				Assembly.Load("HomeDump.Server.Data"),
				Assembly.Load("HomeDump.Server"));
		}


		/// <summary>
		/// Registers specified assemblies.
		/// </summary>
		private static void RegisterAssemblyTypes(
			ContainerBuilder builder,
			params Assembly[] assemblies)
		{
			// Register all types
			builder
				.RegisterAssemblyTypes(assemblies)
				.ExternallyOwned();

			// Register all classes as the interfaces they implement
			builder
				.RegisterAssemblyTypes(assemblies)
				.AsImplementedInterfaces()
				.ExternallyOwned();

			// Register generic types
			RegisterGenericTypes(builder, assemblies);
		}


		/// <summary>
		/// Registers generic types in specified assemblies.
		/// </summary>
		private static void RegisterGenericTypes(
			ContainerBuilder builder,
			IEnumerable<Assembly> assemblies)
		{
			foreach (Assembly assembly in assemblies)
			{
				foreach (Type type in assembly.GetTypes().Where(t => t.IsGenericType))
				{
					foreach (Type interfaceType in type.GetInterfaces().Where(t => t.IsGenericType))
					{
						builder
							.RegisterGeneric(type)
							.As(interfaceType)
							.ExternallyOwned();
					}
				}
			}
		}
	}
}
